package com.ruicar.afs.cloud.manage.finance.bankarrive.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.security.service.AfsUser;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.data.lock.anno.Lock;
import com.ruicar.afs.cloud.common.modules.contract.enums.AccountRegistStatusEnum;
import com.ruicar.afs.cloud.common.modules.contract.enums.ValidOrInvalidEnum;
import com.ruicar.afs.cloud.common.modules.constant.VoucherBuriedPointNo;
import com.ruicar.afs.cloud.common.modules.contract.enums.YesOrNoEnum;
import com.ruicar.afs.cloud.common.mq.finance.corporate.dto.GeneraSuccessDto;
import com.ruicar.afs.cloud.common.mq.rabbit.message.AfsTransEntity;
import com.ruicar.afs.cloud.common.mq.rabbit.message.MqTransCode;
import com.ruicar.afs.cloud.common.util.EmptyUtils;
import com.ruicar.afs.cloud.manage.finance.bankarrive.entity.ManageAccountRegister;
import com.ruicar.afs.cloud.manage.finance.bankarrive.entity.ManageBankAccount;
import com.ruicar.afs.cloud.manage.finance.bankarrive.mapper.ManageAccountRegisterMapper;
import com.ruicar.afs.cloud.manage.finance.bankarrive.service.ManageAccountRegisterService;
import com.ruicar.afs.cloud.manage.finance.bankarrive.service.ManageBankAccountService;
import com.ruicar.afs.cloud.manage.mq.sender.ManageSender;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author: Lee
 * @date 2020-05-30 04:45:15
 * @description
 */
@Service
@Slf4j
@AllArgsConstructor
public class ManageAccountRegisterServiceImpl extends ServiceImpl<ManageAccountRegisterMapper, ManageAccountRegister> implements ManageAccountRegisterService {

    private final ManageBankAccountService manageBankAccountService;
    private final ManageSender manageSender;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ManageAccountRegister>  handleExcelImport(MultipartFile file,Date batchDate) throws Exception {

        List<ManageAccountRegister> accountRegisterList = new ArrayList<>();

        XSSFWorkbook xssFWorkbook = new XSSFWorkbook(file.getInputStream());

        /**  解析excel by ZC.GUO  **/
        accountRegisterList = this.importExcelFileForXss(xssFWorkbook,batchDate);

        if (EmptyUtils.isNotEmpty(accountRegisterList)) {
            this.saveBatch(accountRegisterList);
        }
        return accountRegisterList;
    }


    /**
     * 解析excel
     * @author ZC.GUO
     * @param
     * @return
     */
    private List<ManageAccountRegister>  importExcelFileForXss(XSSFWorkbook xssFWorkbook,Date batchDate) throws Exception {
        List<ManageAccountRegister> accountRegisterList = new ArrayList<>();

        /**  创建工作表 by ZC.GUO  **/
        Sheet sheet = xssFWorkbook.getSheetAt(0);
        List<String> ebankNoList = new ArrayList<>();

        int end = sheet.getLastRowNum();
        if (end > 500){
            throw new AfsBaseException("记录条数不得大于500条，请检查");
        }
        for (int i = 1; i <= end; i++) {
            /**  逐行解析 by ZC.GUO  **/
            ManageAccountRegister accountRegister = this.praseRow(sheet.getRow(i), i);

            /**  重复校验 by ZC.GUO  **/
            ManageAccountRegister manageAccountRegister = this.getOne(Wrappers.<ManageAccountRegister>query().lambda()
                    .eq(ManageAccountRegister::getEbankNo, accountRegister.getEbankNo())
                    .ne(ManageAccountRegister::getStatus, AccountRegistStatusEnum.WRITE_BACK)
                    .ne(ManageAccountRegister::getStatus, AccountRegistStatusEnum.REFUND)
            );
            if (manageAccountRegister != null) {
                throw new AfsBaseException("第" + (i + 1) + "行网银编号已存在于系统中，请检查");
            }

            /**  同文件重复校验 by ZC.GUO  **/
            if (ebankNoList.contains(accountRegister.getEbankNo())) {
                throw new AfsBaseException("文件中存在重复的网银编号，重复网银标号为:" + accountRegister.getEbankNo());
            } else {
                ebankNoList.add(accountRegister.getEbankNo());
            }

            /**  账号判断 by ZC.GUO  **/
            ManageBankAccount bankAccount = manageBankAccountService.getOne(Wrappers.<ManageBankAccount>query().lambda()
                    .eq(ManageBankAccount::getAccount, accountRegister.getBankAccount())
            );
            if (bankAccount == null) {
                throw new AfsBaseException("第" + (i + 1) + "行到账账号未存在于系统中，请检查或进行维护");
            } else {
                if (ValidOrInvalidEnum.invalid.equals(bankAccount.getStatus())) {
                    throw new AfsBaseException("第" + (i + 1) + "行到账账号已失效，请检查或进行维护");
                }
            }

            accountRegister.setReceivingBank(bankAccount.getBankCode());
            accountRegister.setStatus(AccountRegistStatusEnum.NOT_GENERA);
            accountRegister.setIsOperating(YesOrNoEnum.no);
            accountRegister.setBusinessTime(batchDate);
            /**  数据归集 by ZC.GUO  **/
            accountRegisterList.add(accountRegister);
        }
        return accountRegisterList;
    }

    /**
     * 将excel某一行解析为一条到账登记记录
     * @author ZC.GUO
     * @param
     * @return
     */
    private ManageAccountRegister praseRow(Row row,int i) throws Exception{
        ManageAccountRegister accountRegister = new ManageAccountRegister();
        int j= 0;
        /**  网银编号 by ZC.GUO  **/
        String ebankNo;
        if ( CellType.STRING.equals(row.getCell(j).getCellTypeEnum())){
            ebankNo = row.getCell(j).getRichStringCellValue().toString();
            if (EmptyUtils.isEmpty(ebankNo)){
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列为空，请检查");
            }
        }else{
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为文本");
        }
        accountRegister.setEbankNo(ebankNo);
        j++;

        /**  到账时间 by ZC.GUO  **/
        Date arrivalTime;
        if ( CellType.STRING.equals(row.getCell(j).getCellTypeEnum())){
            String arrivalTimeStr = row.getCell(j).getRichStringCellValue().toString();
            try {
                arrivalTime = new SimpleDateFormat("yyyy-MM-dd").parse(arrivalTimeStr);
            } catch (ParseException e) {
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为文本,日期格式为yyyy-MM-dd");
            }
            if (EmptyUtils.isEmpty(arrivalTime)){
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列为空，请检查");
            }
        }else{
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为文本,日期格式为yyyy-MM-dd");
        }
        boolean flag = DateUtil.endOfDay(arrivalTime).getTime()>DateUtil.endOfDay(DateUtil.parseDate(DateUtil.now())).getTime();
        if (flag){
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列,到账时间大于当前日期，请检查");
        }
        accountRegister.setArrivalTime(arrivalTime);
        j++;

        /**  到账账号 by ZC.GUO  **/
        String bankAccount;
        if ( CellType.STRING.equals(row.getCell(j).getCellTypeEnum())){
            bankAccount = row.getCell(j).getRichStringCellValue().toString();
            if (EmptyUtils.isEmpty(bankAccount)){
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列为空，请检查");
            }
        }else{
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为文本");
        }
        accountRegister.setBankAccount(bankAccount);
        j++;

        /**  打款客户 by ZC.GUO  **/
        String paymentCust;
        if ( CellType.STRING.equals(row.getCell(j).getCellTypeEnum())){
            paymentCust = row.getCell(j).getRichStringCellValue().toString();
            if (EmptyUtils.isEmpty(paymentCust)){
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列为空，请检查");
            }
        }else{
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为文本");
        }
        accountRegister.setPaymentCust(paymentCust);
        j++;

        /**  客户账号 by ZC.GUO  **/
        String custAccount;
        if ( CellType.STRING.equals(row.getCell(j).getCellTypeEnum())){
            custAccount = row.getCell(j).getRichStringCellValue().toString();
            if (EmptyUtils.isEmpty(custAccount)){
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列为空，请检查");
            }
        }else{
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为文本");
        }
        accountRegister.setCustAccount(custAccount);
        j++;

        /**  到账金额 by ZC.GUO  **/
        BigDecimal receivedAmt;
        if ( CellType.NUMERIC.equals(row.getCell(j).getCellTypeEnum())){
            receivedAmt = BigDecimal.valueOf(row.getCell(j).getNumericCellValue());
            if (EmptyUtils.isEmpty(receivedAmt)){
                throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列为空，请检查");
            }
        }else{
            throw new AfsBaseException("第"+(i+1)+"行第"+(j+1)+"列格式格式错误,需要格式为数字");
        }
        accountRegister.setReceivedAmt(receivedAmt);
        j++;

        /**  摘要 by ZC.GUO  **/
        String summary = null;
        if (EmptyUtils.isNotEmpty(row.getCell(j).getRichStringCellValue()) && CellType.STRING.equals(row.getCell(j).getCellTypeEnum())){
            summary = row.getCell(j).getRichStringCellValue().toString();
        }
        accountRegister.setSummary(summary);
        j++;
        return accountRegister;
    }
    @Override
    @Lock(keyConstant = ":accountRegister", keys = "#manageAccountRegister.id")
    @Transactional(rollbackFor = Exception.class)
    public void handleAccountRegister(ManageAccountRegister manageAccountRegister) {
        ManageAccountRegister accountRegister = this.getById(manageAccountRegister.getId());
        Assert.isTrue(AccountRegistStatusEnum.NOT_GENERA.equals(accountRegister.getStatus()),"该未知收款状态不是未生成凭证");
        accountRegister.setStatus(AccountRegistStatusEnum.ALREADY_GENERA);
        this.updateById(accountRegister);
        /**  发送记录到账务服务 by ZC.GUO  **/
        GeneraSuccessDto generaSuccessDto = new GeneraSuccessDto();
        AfsUser user = SecurityUtils.getUser();
        generaSuccessDto.setOperator(user == null ? null : user.getUsername());
        generaSuccessDto.setFundId(manageAccountRegister.getId());
        generaSuccessDto.setAmount(manageAccountRegister.getReceivedAmt());
        generaSuccessDto.setFeeSourceTable(ManageAccountRegister.class.getAnnotation(TableName.class).value());
        generaSuccessDto.setSourceAccount(manageAccountRegister.getCustAccount());
        generaSuccessDto.setCreditAccount(manageAccountRegister.getBankAccount());
        generaSuccessDto.setContractNo(manageAccountRegister.getContractNo());
        generaSuccessDto.setBuriedPointNo(VoucherBuriedPointNo.unknownCollection);
        AfsTransEntity<GeneraSuccessDto> entity = new AfsTransEntity<>();
        entity.setData(generaSuccessDto);
        entity.setTransCode(MqTransCode.AFS_CONTRACT_MANAGE_FINANCE_CONTRACT_GENERA_SUCCESS);
        manageSender.sendGeneraSuccessDataToFinance(entity);
    }
    @Override
    public void handleAccountRegisterStatus(List<ManageAccountRegister> manageAccountRegisterList) {
        for (ManageAccountRegister manageAccountRegister : manageAccountRegisterList) {
            this.handleAccountRegister(manageAccountRegister);
        }

    }

    @Override
    public void unlockAccountRegister(List<Long> idList) {
        baseMapper.updateWhenOperate(YesOrNoEnum.no,idList);
    }

    @Override
    public boolean lockAccountRegister(List<Long> idList) {
        List<Long> successIdList = new ArrayList<>();
        for (Long id : idList){
            int count = baseMapper.lockAccountRegister(YesOrNoEnum.yes,id);
            if(count == 0) {
                log.info("银行到账记录锁定失败，id:[{}]", new Object[]{id});
                break;
            }else{
                successIdList.add(id);
            }
        }
        if (successIdList.size() == idList.size()){
            return true;
        }else{
            for (Long id : successIdList){
                baseMapper.lockAccountRegister(YesOrNoEnum.no,id);
            }
            return false;
        }
    }
}
